package com.tcp2.net;


import com.tcp2.server.DxsConfig;
import com.tcp2.server.ProtoMsg;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * Author: 程行荣
 * Time: 2013-07-29 10:49
 * Copyright (C) 2013 Xiamen Yaxon Networks CO.,LTD.
 */

public class ProtoMsgEncoder extends MessageToByteEncoder<ProtoMsg> {
    private DxsConfig config;

    public ProtoMsgEncoder(DxsConfig dtsConfig) {
        config = dtsConfig;
    }



    @Override
    protected void encode(ChannelHandlerContext ctx, ProtoMsg msg, ByteBuf out) throws Exception {
        int msgLen = 0; //消息长度，最后再计算

        ByteBuf tmpBuf = Unpooled.buffer();  //存放消息头和消息体数据
        int startIndex = tmpBuf.writerIndex();
        tmpBuf.writeInt(msgLen);
        tmpBuf.writeInt(msg.msgSn);
        tmpBuf.writeShort(msg.msgId);
        tmpBuf.writeInt(msg.gnssCenterId);
        tmpBuf.writeByte(0).writeByte(0).writeByte(0); //协议版本号标识
        tmpBuf.writeByte(0); //加密标识，不加密
        tmpBuf.writeInt(0); //加密密钥
        if (msg.msgData != null) {
            tmpBuf.writeBytes(msg.msgData);//消息体数据
        }
        msgLen = tmpBuf.writerIndex() - startIndex + 4; //消息长度包括：头标识(1)，尾标识(1)和CRC校验码(2)
        tmpBuf.setInt(startIndex, msgLen); //重新写入实际的消息长度

        out.writeByte(0x5b);//头标识字符
        int crc = 0xffff;          // initial value
        int polynomial = 0x1021;   // 0001 0000 0010 0001  (0, 5, 12)
        int dataLen = tmpBuf.readableBytes();
        for (int j = 0; j < dataLen; j++) {
            byte b = tmpBuf.readByte();
            writeByte(b, out);

            for (int i = 0; i < 8; i++) {
                boolean bit = ((b   >> (7-i) & 1) == 1);
                boolean c15 = ((crc >> 15    & 1) == 1);
                crc <<= 1;
                if (c15 ^ bit) crc ^= polynomial;
            }
        }

        crc &= 0xffff;
        //CRC校验码，2字节，先写入高字节
        writeByte((byte)((crc & 0xff00) >> 8), out);
        writeByte((byte) (crc & 0x00ff), out);

        out.writeByte(0x5d);//尾标识字符
        tmpBuf.release();
    }

    private void writeByte(byte b, ByteBuf out) {
        switch (b) {
            case 0x5b:
                out.writeByte(0x5a);
                out.writeByte(0x01);
                break;
            case 0x5a:
                out.writeByte(0x5a);
                out.writeByte(0x02);
                break;
            case 0x5d:
                out.writeByte(0x5e);
                out.writeByte(0x01);
                break;
            case 0x5e:
                out.writeByte(0x5e);
                out.writeByte(0x02);
                break;
            default:
                out.writeByte(b);
                break;
        }
    }
}
